package cc.linker.steplink.crm.service.impl;

import cc.linker.steplink.crm.commons.Constants;
import cc.linker.steplink.crm.commons.http.HttpService;
import cc.linker.steplink.crm.commons.model.SystemProperties;
import cc.linker.steplink.crm.dao.*;
import cc.linker.steplink.crm.domain.*;
import cc.linker.steplink.crm.merchant.dao.PersonnelDao;
import cc.linker.steplink.crm.merchant.dao.PublicMenuDao;
import cc.linker.steplink.crm.merchanth5.dao.VipCustomerLogDao;
import cc.linker.steplink.crm.merchanth5.dao.WxShareDao;
import cc.linker.steplink.crm.merchanth5.service.SurvivalPushService;
import cc.linker.steplink.crm.response.GlobalException;
import cc.linker.steplink.crm.response.ResponseException;
import cc.linker.steplink.crm.service.EventMsgService;
import cc.linker.steplink.crm.service.PersonalService;
import com.mongodb.util.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static cc.linker.steplink.crm.merchanth5.controller.OverViewInfoController.INTERACTION;
import static cc.linker.steplink.crm.merchanth5.controller.OverViewInfoController.NEW_SUBSCRIBE;

@Slf4j
@Service
public class EventMsgServiceImpl2 implements EventMsgService {
    @Autowired
    private EventMsgDao eventMsgDao;
    @Autowired
    private PersonalDao personalDao;
    @Autowired
    private PersonalService personalService;
    @Autowired
    private CustomerDao customerDao;
    @Autowired
    private CustomerInfoDao customerInfoDao;
    @Autowired
    private CustomerInfoWxDao customerInfoWxDao;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SystemProperties systemProperties;
    @Autowired
    private HttpService httpService;
    @Autowired
    private ActionLogDao actionLogDao;
    @Autowired
    private WxShareDao wxShareDao;
    @Autowired
    private SurvivalPushService survivalPushService;
    @Autowired
    private PublicMenuDao publicMenuDao;
    @Autowired
    private VipCustomerLogDao vipCustomerLogDao;
    @Autowired
    private PersonnelDao personnelDao;

    @Value("${spring.mail.username}")
    private String emailUserName;
    @Value("${spring.mail.password}")
    private String emailUserPassword;
    private final static String wxAction = "getWeixinUserInfo";

    @Override
    public void saveEvent(Map<String, Object> map) {
        /**
         * {
         *   "CreateTime": "1598323394",
         *   "token": "gh_2b949dcfd84a",
         *   "openId": "oQ9-51IlsnrWJ8y7Vqtpq4dm1ixs",
         *   "MsgType": "event",
         *   "EventType": "CLICK",
         *   "EventKey": "1295322872",
         *   "tag":"wxSystem"
         * }
         */
        if (!map.containsKey("tag")) {
            //除微信矩阵其他系统调用不执行
            return;
        }
        LOGGER.info("saveEvent---------------->" + com.alibaba.fastjson.JSON.toJSONString(map));
        LOGGER.info("推送官方email账户：---------------->" + emailUserName);
        LOGGER.info("推送官方email密码：---------------->" + emailUserPassword);

        if (map.containsKey("token") && map.containsKey("openId")) {
            String token = (String) map.get("token");
            String openId = (String) map.get("openId");
            String eventType = (String) map.get("EventType");
            String msgType = (String) map.get("MsgType");

            // 用户取消关注
            if (StringUtils.equalsIgnoreCase(eventType, Constants.WXEventType.UNSUBSCRIBE)) {
                publicMenuDao.removeCancelAttentionCustomer(openId);
                //todo  【千人计划】取消关注到逻辑业务中
                DemoWxCancel(openId);
            }

            // 查询机构OrgCode，根据推荐人的openId，查询当前关注该公众号的用户ID
            // TODO 当前的设定：openId该参数是必填
            String orgId = eventMsgDao.getOrgIdByToken(token);
            String customerId = personalDao.getCustomerIdByOpenIdAndOrgId(openId, orgId);
            if (StringUtils.isNotEmpty(customerId)) {
                // 保存用户缓存信息
                saveEventWithCustomerID(customerId, orgId, token, openId, eventType, msgType, map);
            } else {
                // 创建用户信息，返回用户的customerId
                customerId = saveEventWithoutCustomerID(orgId, token, openId, eventType, msgType);
            }

            // 进行通用的消息事件处理
            saveCommonEvent(customerId, orgId, token, openId, eventType, msgType, map);
        }
    }


    /**
     * 【千人计划】 微信取消关注逻辑 todo 添加 关注后 取消关注的状态值
     */
    public void DemoWxCancel(String openId) {

        LOGGER.info("【千人计划取消关注逻辑开始】=====> 参数openId为 ：" + openId);

        try {
            Map<String, Object> map = new HashMap<>();
            map.put("wecomeStatus", 2); //2表示关注后取消的
            map.put("readTime", new Date());
            map.put("openId", openId);

            //根据openId 将绑定的邮件 微信绑定状态变成未关注
            personnelDao.updateEmailStatusByOpenId(map);

            //根据openId找到邮件分组的ids(因为有分组的概念)
            List<String> precisePidByOpenId = personnelDao.getPrecisePidsByOpenId(openId);

            LOGGER.info("【千人计划取消关注】=====> 参数orgId为 ：" + precisePidByOpenId);

            //添加取消关注动作到日志表中
            if (precisePidByOpenId.size() > 0) {
                List<Map<String, Object>> logList = new ArrayList<>();

                Map<String, Object> logMap = new HashMap<>();
                for (String precisePIds : precisePidByOpenId) {
                    logMap.put("pid", precisePIds);
                    logMap.put("readType", Constants.PreciseLogReadType.WX_CANCEL);
                    map.put("readTime", new Date());
                    logList.add(logMap);
                }
                LOGGER.info("【千人计划取消关注】=====> [] ：" + logList);

                personnelDao.addWxCancelReadLog(logList);
            }
        } catch (Exception e) {
            LOGGER.info("取消关注 千人计划逻辑错误" + e);
        }


    }

    private void setLastInteractionTime(String customerId, String eventKey) {
        List<Map<String, Object>> activeLog = wxShareDao.getCustomerActiveLog(customerId);
        if (null != activeLog && activeLog.size() > 0) {
            for (Map<String, Object> al : activeLog) {
                String orgId = al.get("orgId").toString();
                String logId = al.get("id").toString();
                String action = al.get("action").toString();
                String actionTime = al.get("actionTime").toString();
                String artId = "";
                if (!org.springframework.util.StringUtils.isEmpty(al.get("artId"))) {
                    artId = al.get("artId").toString();
                }
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String lastInteractionTime = sdf.format(new Date());
                survivalPushService.setPushSurvival(customerId, logId, action, actionTime, lastInteractionTime, orgId, artId, eventKey);
            }
        }
    }

    private String saveEventWithoutCustomerID(String orgId, String token,
                                              String openId, String eventType, String msgType) {
        String customerId = null;
        // 事件消息处理
        if (StringUtils.equalsIgnoreCase(msgType, Constants.WXMsgType.EVENT)) {
            if (StringUtils.equalsIgnoreCase(eventType, Constants.WXEventType.SUBSCRIBE)) {
                //TODO 当前业务下globalOpenid和openId是同一个
                personalService.saveWxH5User(openId, token, openId);
                customerId = personalDao.getCustomerIdByOpenIdAndOrgId(openId, orgId);
                redisTemplate.opsForHash().increment(NEW_SUBSCRIBE, orgId, 1);
            }
        }
        return customerId;
    }

    private void saveEventWithCustomerID(String customerId, String orgId, String token,
                                         String openId, String eventType, String msgType, Map<String, Object> map) {
        //缓存用户互动
        String strNow = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        redisTemplate.opsForSet().add(INTERACTION + strNow + "_" + orgId, customerId);
        redisTemplate.expire(INTERACTION + strNow + "_" + orgId, 31, TimeUnit.DAYS);
        String key = INTERACTION + orgId + "_" + customerId;
        redisTemplate.opsForValue().set(key, "1", 30, TimeUnit.DAYS);

        // 丰富Map的值，数据库保存用户的操作事件
        LocalDateTime dateTime = LocalDateTime.ofEpochSecond(Long.valueOf((String) map.get("CreateTime")), 0, ZoneOffset.ofHours(8));
        String s = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        map.put("CreateTime", s);
        map.put("customerId", customerId);
        // 自定义菜单接口中KEY值对应，很有可能是JSON数据，将用户的点击的事件进行保存
        Object eventKey = map.get("EventKey");
        if (!(eventKey instanceof String)) {
            String serialize = JSON.serialize(eventKey);
            map.put("EventKey", serialize);
        }
        eventMsgDao.saveEvent(map);


        Map<String, Object> sub = new HashMap<>();
        sub.put("customerId", customerId);

        // 如果当前的操作事件中有用户的event事件，进行事件处理
        if (StringUtils.equalsIgnoreCase(msgType, Constants.WXMsgType.EVENT)) {

            // 用户menu点击事件判断
            String menuKey = Constants.WXMenuKey.PUBLIC_MENU_TOKEN + token;
            String menuSta = redisTemplate.opsForValue().get(menuKey);
            if (StringUtils.isNotEmpty(menuSta)) {
                if ("CLICK".equals(map.get("EventType")) && !map.get("EventKey").toString().startsWith("clickPushEvent*")) {
                    //菜单事件推送到mq
                    Map<String, Object> mqParam = new HashMap<>();
                    mqParam.put("customerId", customerId);
                    mqParam.put("eventTime", s);
                    mqParam.put("eventKey", map.get("EventKey"));
                    mqParam.put("token", map.get("token"));
                    mqParam.put("openId", map.get("openId"));
                }
            }

            // 更新关注时间，取关后重新关注会覆盖时间
            if (StringUtils.equalsIgnoreCase(eventType, Constants.WXEventType.SUBSCRIBE)) {
                Action action = new Action();
                action.setActionId(UUID.randomUUID().toString());
                action.setActionFollowTime(new Date());
                action.setCustomerId(customerId);
                action.setOpenid(openId);
                action.setToken(token);
                actionLogDao.insertUpdateAction(action);

                // 更新用户关注状态-用户重新关注，更新subscribe状态
                sub.put("subscribe", 1);
                customerDao.updateSubscribeByCustomerId(sub);
                redisTemplate.opsForHash().increment(NEW_SUBSCRIBE, orgId, 1);

                // 更新用户信息
                WxUserInfoDto wxUserInfoDto;
                Map<String, Object> params = new HashMap<>();
                params.put("action", wxAction);
                params.put("openid", openId);
                params.put("token", token);
                //获取微信用户信息-重新获取微信用户信息进行数据库更新
                String result = null;
                try {
                    result = httpService.doPost(systemProperties.getWxpushurl(), com.alibaba.fastjson.JSON.toJSONString(params));
                } catch (URISyntaxException | IOException e) {
                    LOGGER.error("调用微信矩阵信息失败");
                    LOGGER.error("请求地址[{}]\n请求参数[{}]\n返回结果[{}]", systemProperties.getWxpushurl(), params, result);
                    throw GlobalException.build("获取用户信息异常");
                }
                if (StringUtils.isEmpty(result)) {
                    throw GlobalException.build("获取用户信息异常");
                }
                try {
                    wxUserInfoDto = com.alibaba.fastjson.JSON.parseObject(result, WxUserInfoDto.class);
                } catch (Exception e) {
                    LOGGER.error("矩阵返回数据转为对象失败" + result, e);
                    throw GlobalException.build("获取用户信息异常");
                }
                if (wxUserInfoDto.getErrcode().equals("200")) {

                    WxUserInfo wxUserInfo = wxUserInfoDto.getData();
                    String area = "";
                    if (!StringUtils.isEmpty(wxUserInfo.getCountry()) && !"null".equals(wxUserInfo.getCountry())) {
                        area += wxUserInfo.getCountry();
                    }
                    area += "@";
                    if (!StringUtils.isEmpty(wxUserInfo.getProvince()) && !"null".equals(wxUserInfo.getProvince())) {
                        area += wxUserInfo.getProvince();
                    }
                    area += "@";
                    if (!StringUtils.isEmpty(wxUserInfo.getCity()) && !"null".equals(wxUserInfo.getCity())) {
                        area += wxUserInfo.getCity();
                    }

                    Customer customer = new Customer();
                    customer.setCustomerId(customerId);
                    customer.setCustomerName(wxUserInfo.getNickname());
                    customer.setCustomerAvatar(wxUserInfo.getHeadimgurl());
                    customerDao.updateByPrimaryKeySelective(customer);

                    //客户拓展信息
//                            CustomerInfo customerInfo = new CustomerInfo();
//                            customerInfo.setCustomerArea(area);
//                            customerInfo.setCustomerId(customerId);
//                            customerInfoDao.updateByCustomerIdSelective(customerInfo);

                    //客户微信信息
                    CustomerInfoWx customerInfoWx = new CustomerInfoWx();
                    if (wxUserInfo.getSex() != null) {
                        customerInfoWx.setWxGender(wxUserInfo.getSex().byteValue());
                    }
                    customerInfoWx.setWxAddress(area);
                    customerInfoWx.setWxName(wxUserInfo.getNickname());
                    customerInfoWx.setWxAvatar(wxUserInfo.getHeadimgurl());
                    customerInfoWx.setCustomerId(customerId);
                    customerInfoWxDao.updateByPrimaryKeySelective(customerInfoWx);
                } else {
                    throw new GlobalException(new ResponseException(400, wxUserInfoDto.getMsg()));
                }

            } else if ("unsubscribe".equals(map.get("EventType"))) {
                sub.put("subscribe", 0);
                customerDao.updateSubscribeByCustomerId(sub);
            }
        } else if (StringUtils.equalsIgnoreCase(msgType, Constants.WXMsgType.TEXT)) {
            // 记录用户对话行为
            Action action = new Action();
            action.setActionId(UUID.randomUUID().toString());
            action.setActionTalkTime(new Date());
            action.setCustomerId(customerId);
            action.setOpenid(openId);
            action.setToken(token);
            actionLogDao.insertUpdateAction(action);
        }
    }

    private void saveCommonEvent(String customerId, String orgId, String token,
                                 String openId, String eventType, String msgType, Map<String, Object> map) {
        // 用户关注事件处理
        if ("subscribe".equals(eventType)) {
            if (null != map.get("EventKey")) {
                //关注事件取事件key值
                String eventKeys = (String) map.get("EventKey");
                LOGGER.info("email邮件回调原始eventKeys---------------->" + eventKeys);
                eventKeys = eventKeys.replace("qrscene_", "");
                LOGGER.info("email邮件回调更改eventKeys---------------->" + eventKeys);

                // TODO 添加参数前缀的判断：email开头【添加的是demo演示，客户信息更新用户的邮箱信息】
                if (StringUtils.startsWithIgnoreCase(eventKeys, Constants.WXQrCodeMail.MAIL_PREFIX)) {
                    // TODO 将email信息和邮件信息结合在一起
                    LOGGER.info("email邮件分享关注Map---------------->" + com.alibaba.fastjson.JSON.toJSONString(map));
                    LOGGER.info("email邮件分享关注String---------------->eventKeys：" + eventKeys);

                    // 取出真实email参数：email:tang_zhifeng@hzlh.com&OrgID:10097&TaskID:11111
                    // 进行参数获取
                    String[] split = eventKeys.split(Constants.WXQrCodeMail.ORG_NOTICE);
                    if (ArrayUtils.getLength(split) != 2) {
                        throw new GlobalException(new ResponseException(400, "邮箱绑定二维码参数不合法"));
                    }
                    // 取出组装的参数
                    String email = split[0].replace(Constants.WXQrCodeMail.MAIL_PREFIX, "");
                    String[] orgIdAndTaskId = split[1].split(Constants.WXQrCodeMail.TASK_ID_NOTICE);
                    String taskId = orgIdAndTaskId[1];

                    // TODO 用户信息表中添加openId，customerId[后续可以根据这两个参数查询用户信息]
                    map.put("customerId", customerId);
                    map.put("openId", openId);
                    map.put("orgId", orgId);
                    map.put("email", email);
                    map.put("taskId", taskId);
                    personnelDao.updateWxSubscribeData(map);


                    // TODO 更新邮件的微信绑定结果【此时将微信和邮件建立绑定关系】
                    //改变当前当前用户邮件状态变为已读
                    map.put("wecomeStatus", 1);
                    map.put("attentionTime", new Date());

                    //TODO 后续添加微信的关注时间
                    personnelDao.updateEmailStatus(map);

                    //更新日志表
                    //根据 taskId和email找到任务id
                    int pidByEmailAndTaskId = personnelDao.getPidByEmailAndTaskId(map);
                    map.put("readType", Constants.PreciseLogReadType.WX_BIND);
                    map.put("pid", pidByEmailAndTaskId);

                    personnelDao.addReadLog(map);


                } else if (!eventKeys.equals(customerId)) {
                    // 【对应saveshare方法，用户分享后用户扫码关注】
                    LOGGER.info("email对应saveshare方法，用户分享后用户扫码关注---------------->eventKeys：" + eventKeys);
                    survivalPushService.saveShareCache(eventKeys, "subscribe", orgId, customerId);
                } else {
                    LOGGER.info("email进入到其他方法---------------->");
                }
            }
        }
        // 用户消息事件处理
        if ("event".equals(msgType)) {
            if ("SCAN".equals(eventType) || "subscribe".equals(eventType) || ("CLICK".equals(eventType) && map.get("EventKey").toString().startsWith("clickPushEvent*"))) {
                Map<String, Object> activeParams = new HashMap<>();
                activeParams.put("openId", openId);
                activeParams.put("token", token);
                activeParams.put("customerId", customerId);
                activeParams.put("action", map.get("EventType"));
                activeParams.put("orgId", orgId);
                String eventKey = "";
                if (null != map.get("EventKey")) {
                    eventKey = map.get("EventKey").toString();
                }
                activeParams.put("articleId", eventKey);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String lastInteractionTime = sdf.format(new Date());
                activeParams.put("lastInteractionTime", lastInteractionTime);
                wxShareDao.addcactivelog(activeParams);
            }
        }
        //更新用户最后活跃时间
        wxShareDao.setCustomerLastInteraction(customerId);
        if (!"unsubscribe".equals(map.get("EventType"))) {
            this.setLastInteractionTime(customerId, map.get("EventKey") == null ? null : map.get("EventKey").toString());
        }
    }
}
